/*
 * HttpProtocol.cpp
 *
 */

#include "HttpProtocol.h"
#include "HttpStringBody.h"
#include "HttpHeader.h"
#include "HttpParser.h"
#include <sstream>

HttpProtocol::HttpProtocol(Socket& socket): socket(socket) {
	bodyBuffer.resize(BODY_BUFFER_SIZE);
	request = NULL;
}

HttpProtocol::~HttpProtocol() {
	if(this->request != NULL)
		delete this->request;
}

const HttpRequest* HttpProtocol::recvRequest() {
	std::string line;
	recvLine(line);
	setRequest(HttpParser::parseRequest(line));
	recvHeaders(request);
	if (request->hasBody()) {
		std::stringstream buffer;
		size_t size;
		buffer << request->getHeader(HEADER_CONTENT_LENGTH);
		buffer >> size;
		recvBody(request, size);
	}
	return request;
}

void HttpProtocol::setRequest(HttpRequest* request) {
	if(this->request != NULL)
		delete this->request;
	this->request = request;
}

void HttpProtocol::sendResponse(HttpResponse& response) {
	std::string statusLine = response.getStatusLine();
	sendLine(statusLine);
	sendHeaders(response);
	if (response.hasBody()) {
		sendLine(HttpMessage::CRLF);
		sendBody(response.getBody());
	}
}

void HttpProtocol::sendHeaders(HttpResponse& response) {
	std::list<HttpHeader*>::const_iterator it;
	for (it = response.getAllHeaders().begin();
			it != response.getAllHeaders().end(); ++it) {
		sendLine((*it)->getHeaderLine());
	}
}

void HttpProtocol::sendBody(HttpBody& body) {
	size_t size = body.getSize();
	size_t sent = 0;
	size_t read = 1;
	size_t total = 0;
	std::istream& stream = body.getStream();
	while (total < size && read > 0) {
		stream.read(&bodyBuffer[0], BODY_BUFFER_SIZE);
		read = stream.gcount();
		while (sent < read) {
			sent += socket.send(&bodyBuffer[sent], read - sent);
		}
		sent = 0;
		total += read;
	}
}

void HttpProtocol::sendLine(const std::string& line) {
	size_t pos;
	size_t toSend = line.length();
	while (toSend > 0) {
		pos = line.length() - toSend;
		toSend -= socket.send(line.data() + pos, toSend);
	}
}

void HttpProtocol::recvLine(std::string& line) {
	line.clear();
	bool end = false;
	char previous;
	char current;
	int recieved = socket.recv(&current, sizeof current);
	while (!end && recieved > 0) {
		previous = current;
		recieved = socket.recv(&current, sizeof current);
		if (previous == HttpMessage::CR || current == HttpMessage::LF)
			end = true;
		else
			line.push_back(previous);
	}
}

void HttpProtocol::recvHeaders(HttpRequest* request) {
	std::string line, nextLine;
	unsigned int begin;
	recvLine(line);
	while (line.length() > 0) {
		recvLine(nextLine);
		begin = nextLine.find_first_not_of(HttpMessage::WHITES);
		while (nextLine.length() > 0 && begin > 0) {
			line += nextLine.substr(begin - 1);
			recvLine(nextLine);
			begin = nextLine.find_first_not_of(HttpMessage::WHITES);
		}
		request->addHeader(HttpParser::parseHeader(line));
		line = nextLine;
	}
}

void HttpProtocol::recvBody(HttpRequest* request, size_t size) {
	if(size <= MAX_REQUEST_BODY_SIZE) {
		std::stringstream buffer("");
		size_t read = 0;
		char aux;
		while (read < size) {
			socket.recv(&aux, sizeof aux);
			buffer << aux;
			++read;
		}
		request->setBody(new HttpStringBody(buffer.str()));
	}
	else
		throw MessageException("Tamaño de pedido supera el límite");
}
